#include "XmlParser.h"
#include "../Common/ZException.h"
#include <functional>

GLOBAL_NAMESPACE_BEGIN

namespace FileTools
{
    XmlParser::XmlParser()
        : document_(NULL)
        , fileName_("")
    {
    }

    XmlParser::XmlParser(const char* fileName)
    {
        document_ = NULL;
        fileName_ = std::string(fileName);
        if (!loadXml(fileName))
            destroy();
    }

    XmlParser::~XmlParser()
    {
        destroy();
    }

    void XmlParser::destroy()
    {
        if (document_)
        {
            delete document_;
        }
        document_ = NULL;
        fileName_ = std::string("");
    }

    bool XmlParser::isValid()
    {
        return document_!=NULL;
    }

    bool XmlParser::loadXml(const char* fileName)
    {
        destroy();
        document_ = new tinyxml2::XMLDocument;
        if (document_->LoadFile(fileName)!=tinyxml2::XML_NO_ERROR)
            return false;

        fileName_ = std::string(fileName);
        return true;
    }

    bool XmlParser::parserConfigFile()
    {
        tinyxml2::XMLElement *scene = document_->RootElement();
        tinyxml2::XMLElement *surface = scene->FirstChildElement("node");
        while (surface)
        {
            tinyxml2::XMLElement *surfaceChild = surface->FirstChildElement();
            const char* content;
            const tinyxml2::XMLAttribute *attributeOfSurface = surface->FirstAttribute();
            std::string name(attributeOfSurface->Name());
            std::string value(attributeOfSurface->Value());
            //mpNodes_[name] = value;
            while (surfaceChild)
            {
                content = surfaceChild->GetText();
                surfaceChild = surfaceChild->NextSiblingElement();
            }
            surface = surface->NextSiblingElement();
        }

        return true;
    }

    std::vector<std::string> XmlParser::collectLevel1Nodes()
    {
        std::vector<std::string> nodeNames;

        tinyxml2::XMLElement* root = document_->RootElement();
        tinyxml2::XMLElement* node = root->FirstChildElement();
        while(node)
        {
            if (node->Name()!=0)
                nodeNames.push_back(node->Name());
            node = node->NextSiblingElement();
        }

        return nodeNames;
    }

    std::string XmlParser::getElementValue(const char* nodeName, const char* name)
    {
        tinyxml2::XMLElement *root = document_->RootElement();
        if (!root) return std::string("");
        tinyxml2::XMLElement *node = root->FirstChildElement(nodeName);
        if (!node) return std::string("");
        const char* value = 0;
        tinyxml2::XMLElement *elem = node->FirstChildElement(name);
        if (elem != 0)
            return std::string(elem->GetText());
        std::string val(value);
        val.erase(std::remove_if(val.begin(), val.end(), std::ptr_fun(std::isspace)), val.end());
        return val;
    }

    int XmlParser::getElementValueToInt(const char* nodeName, const char* name)
    {
        tinyxml2::XMLElement *root = document_->RootElement();
        if (!root) return 0;
        tinyxml2::XMLElement *node = root->FirstChildElement(nodeName);
        if (!node) return 0;

        int ret = 0;
        tinyxml2::XMLElement *elem = node->FirstChildElement(name);
        if (elem == 0)
            ZFW_EXCEPTION(Exception::ERR_INVALID_PARAMS, "Wrong parameter casting.", "XmlParser::getElementValueToInt");
        
        if ( tinyxml2::XMLUtil::ToInt(elem->GetText(), &ret) )
            return ret;
        else
            ZFW_EXCEPTION(Exception::ERR_INVALID_PARAMS, "Wrong parameter casting.", "XmlParser::getElementValueToInt");

    }

    double XmlParser::getElementValueToDouble(const char* nodeName, const char* name)
    {
        tinyxml2::XMLElement *root = document_->RootElement();
        if (!root) return 0;
        tinyxml2::XMLElement *node = root->FirstChildElement(nodeName);
        if (!node) return 0;

        double ret = 0;
        tinyxml2::XMLElement *elem = node->FirstChildElement(name);
        if (elem == 0)
            ZFW_EXCEPTION(Exception::ERR_INVALID_PARAMS, "Wrong parameter casting.", "XmlParser::getAttributeDouble");
        
        if ( tinyxml2::XMLUtil::ToDouble(elem->GetText(), &ret) )
            return ret;
        else
            ZFW_EXCEPTION(Exception::ERR_INVALID_PARAMS, "Wrong parameter casting.", "XmlParser::getAttributeDouble");
    }

    bool XmlParser::getElementValueToBoolean(const char* nodeName, const char* name)
    {
        tinyxml2::XMLElement *root = document_->RootElement();
        if (!root) return 0;
        tinyxml2::XMLElement *node = root->FirstChildElement(nodeName);
        if (!node) return 0;

        bool ret = false;
        tinyxml2::XMLElement *elem = node->FirstChildElement(name);
        if (elem == 0)
            //ZFW_EXCEPTION(Exception::ERR_INVALID_PARAMS, "Wrong parameter casting.", "XmlParser::getElementValueToBoolean");
                return false;
        
        if ( tinyxml2::XMLUtil::ToBool(elem->GetText(), &ret) )
            return ret;
        else
            ZFW_EXCEPTION(Exception::ERR_INVALID_PARAMS, "Wrong parameter casting.", "XmlParser::getElementValueToBoolean");
    }

    std::vector<double> XmlParser::collectElementValusToDouble(const char* nodeName, const char* name)
    {
        std::vector<double> ret;

        tinyxml2::XMLElement *root = document_->RootElement();
        if (!root) return ret;
        tinyxml2::XMLElement *node = root->FirstChildElement(nodeName);
        if (!node) return ret;

        tinyxml2::XMLElement *elem = node->FirstChildElement(name);
        if (elem == 0)
            ZFW_EXCEPTION(Exception::ERR_INVALID_PARAMS, "Wrong parameter casting.", "XmlParser::getElementValueToBoolean");

        double oneData=0;
        tinyxml2::XMLElement *child = elem->FirstChildElement();
        while (child)
        {
            if ( tinyxml2::XMLUtil::ToDouble(child->GetText(), &oneData) )
                ret.push_back(oneData);
            else
                ZFW_EXCEPTION(Exception::ERR_INVALID_PARAMS, "Wrong parameter casting.", "XmlParser::getAttributeDouble");

            child = child->NextSiblingElement();
        }

        return ret;
    }
}

GLOBAL_NAMESPACE_END